#!/usr/bin/env python3
"""严格类型检查功能的单元测试"""

import pytest
from mcpy.compiler import MCPyCompiler


class TestStrictTyping:
    """严格类型检查测试类"""

    def setup_method(self):
        """测试方法初始化"""
        # 启用严格类型检查，禁用文件保存
        self.compiler = MCPyCompiler(
            {"compiler": {"strict_typing": True}, "save_generated": False}
        )

    def test_correct_typing_should_pass(self):
        """测试正确的类型注解应该编译成功"""
        content = '''
from typing import List, Dict

# 正确的模块级别变量类型注解
numbers: List[int] = [1, 2, 3, 4, 5]
data: Dict[str, int] = {"a": 1, "b": 2}

# 正确的函数定义
def process_list(items: List[int]) -> int:
    """处理列表并返回总和"""
    total: int = 0
    for item in items:
        total += item
    return total

def calculate(x: int, y: int) -> int:
    """计算两个数的和"""
    result: int = x + y
    return result

def main() -> None:
    """主函数"""
    result: int = process_list(numbers)
    sum_result: int = calculate(10, 20)
'''
        result = self.compiler.compile_source(content, "test_correct_typing.py")

        assert (
            result.success
        ), f"正确的类型注解应该编译成功，但是失败了: {result.errors}"
        assert not result.errors, "正确的类型注解不应该有错误"

    def test_missing_variable_type_annotation(self):
        """测试变量缺少类型注解应该报错"""
        content = """
# 变量缺少类型注解
numbers = [1, 2, 3, 4, 5]

def main() -> None:
    pass
"""
        result = self.compiler.compile_source(content, "test_missing_variable.py")

        assert not result.success, "变量缺少类型注解应该编译失败"
        assert result.errors, "应该有错误信息"
        assert any(
            "变量 'numbers' 缺少类型注解" in error for error in result.errors
        ), f"应该包含变量类型注解错误，实际错误: {result.errors}"

    def test_generic_type_missing_parameters(self):
        """测试泛型类型缺少参数的处理"""
        content = '''
def process_items(items: list) -> int:
    """测试list类型，现在允许不带参数（映射为mc::variants）"""
    return len(items)

def process_dict(data: dict) -> int:
    """测试dict类型，现在允许不带参数（映射为mc::dict）"""
    return len(data)

def process_tuple(data: tuple) -> int:
    """测试tuple类型，现在允许不带参数（映射为mc::variants）"""
    return len(data)

def process_set(data: set) -> int:
    """测试set类型，现在允许不带参数（映射为mc::variants）"""
    return len(data)
'''
        result = self.compiler.compile_source(content, "test_generic_types.py")

        # 现在所有基础容器类型（list、dict、tuple、set）都被允许，编译应该成功
        assert (
            result.success
        ), f"所有基础容器类型现在都被允许，编译应该成功，实际错误: {result.errors}"

        # 检查是否包含泛型类型错误（现在所有基础容器类型都被允许，不应该报错）
        list_error_found = any(
            "泛型类型 'list' 缺少类型参数" in error for error in result.errors
        )
        tuple_error_found = any(
            "泛型类型 'tuple' 缺少类型参数" in error for error in result.errors
        )
        dict_error_found = any(
            "泛型类型 'dict' 缺少类型参数" in error for error in result.errors
        )
        set_error_found = any(
            "泛型类型 'set' 缺少类型参数" in error for error in result.errors
        )

        assert (
            not list_error_found
        ), f"list类型现在被允许，不应该报错，实际错误: {result.errors}"
        assert (
            not tuple_error_found
        ), f"tuple类型现在被允许，不应该报错，实际错误: {result.errors}"
        assert (
            not dict_error_found
        ), f"dict类型现在被允许，不应该报错，实际错误: {result.errors}"
        assert (
            not set_error_found
        ), f"set类型现在被允许，不应该报错，实际错误: {result.errors}"

    def test_function_missing_parameter_type_annotation(self):
        """测试函数参数缺少类型注解应该报错"""
        content = '''
def calculate(x, y):
    """函数参数缺少类型注解"""
    return x + y

def partial_annotation(x: int, y) -> int:
    """部分参数缺少类型注解"""
    return x + y
'''
        result = self.compiler.compile_source(content, "test_function_params.py")

        assert not result.success, "函数参数缺少类型注解应该编译失败"
        assert result.errors, "应该有错误信息"

        # 检查参数类型注解错误
        param_errors = [
            error
            for error in result.errors
            if "参数" in error and "缺少类型注解" in error
        ]
        assert (
            len(param_errors) >= 3
        ), f"应该至少有3个参数类型注解错误，实际错误: {result.errors}"

    def test_function_missing_return_type_annotation(self):
        """测试函数缺少返回类型注解应该报错"""
        content = '''
def get_message():
    """函数缺少返回类型注解"""
    return "Hello, World!"

def calculate(x: int, y: int):
    """函数缺少返回类型注解"""
    return x + y
'''
        result = self.compiler.compile_source(content, "test_return_types.py")

        assert not result.success, "函数缺少返回类型注解应该编译失败"
        assert result.errors, "应该有错误信息"

        # 检查返回类型注解错误
        return_errors = [
            error
            for error in result.errors
            if "函数" in error and "缺少返回类型注解" in error
        ]
        assert (
            len(return_errors) >= 1
        ), f"应该至少有1个返回类型注解错误，实际错误: {result.errors}"

    def test_comprehensive_strict_typing_errors(self):
        """测试综合的严格类型检查错误"""
        content = """
# 变量缺少类型注解
numbers = [1, 2, 3, 4, 5]

# 函数参数缺少类型注解（另一个例子）
def process_items(items):
    return len(items)

# 函数参数缺少类型注解
def calculate(x, y):
    return x + y

# 函数缺少返回类型注解
def get_message():
    return "Hello, World!"

def main() -> None:
    # 变量缺少类型注解
    message = get_message()
"""
        result = self.compiler.compile_source(content, "test_comprehensive.py")

        assert not result.success, "包含多种错误的代码应该编译失败"
        assert result.errors, "应该有错误信息"

        # 验证收集到了所有类型的错误
        error_types = {
            "variable": False,
            "generic": False,
            "parameter": False,
            "return": False,
        }

        for error in result.errors:
            if "变量" in error and "缺少类型注解" in error:
                error_types["variable"] = True
            elif "泛型类型" in error and "缺少类型参数" in error:
                error_types["generic"] = True
            elif "参数" in error and "缺少类型注解" in error:
                error_types["parameter"] = True
            elif "函数" in error and "缺少返回类型注解" in error:
                error_types["return"] = True

        assert error_types[
            "variable"
        ], f"应该包含变量类型注解错误，实际错误: {result.errors}"
        # 注意：现在基础容器类型（list、dict、tuple、set）都被允许，不再有泛型类型错误
        # assert error_types['generic'], f"应该包含泛型类型错误，实际错误: {result.errors}"
        assert error_types[
            "parameter"
        ], f"应该包含参数类型注解错误，实际错误: {result.errors}"
        assert error_types[
            "return"
        ], f"应该包含返回类型注解错误，实际错误: {result.errors}"

        # 验证错误数量合理（应该收集到多个错误，但不包括泛型类型错误）
        assert (
            len(result.errors) >= 5
        ), f"应该收集到至少5个错误，实际收集到: {len(result.errors)}"

    def test_temporary_variables_should_be_ignored(self):
        """测试临时变量以及返回值为None的函数应该被忽略"""
        content = """
# 常见的临时变量以及返回值为None的函数
_ = "temporary"
i = 0
j = 1
temp = "temp value"
tmp = "tmp value"
result = "result value"

def main():
    pass
"""
        result = self.compiler.compile_source(content, "test_temp_vars.py")

        assert (
            result.success
        ), f"临时变量应该被忽略，编译应该成功，但是失败了: {result.errors}"
        assert not result.errors, "临时变量不应该产生错误"

    def test_class_methods_strict_typing(self):
        """测试类方法的严格类型检查"""
        content = """
class WrongClass:
    def __init__(self, value):  # 缺少参数类型注解和返回类型注解
        self.value = value
    
    def get_value(self):  # 缺少返回类型注解
        return self.value
    
    def process_data(self, data):  # 缺少参数类型注解
        return len(data)

class CorrectClass:
    def __init__(self, value: int) -> None:
        self.value: int = value
    
    def get_value(self) -> int:
        return self.value
"""
        result = self.compiler.compile_source(content, "test_class_methods.py")

        assert not result.success, "类方法缺少类型注解应该编译失败"
        assert result.errors, "应该有错误信息"

        # 验证包含类方法相关的错误
        method_errors = [
            error
            for error in result.errors
            if any(keyword in error for keyword in ["参数", "函数"])
        ]
        assert (
            len(method_errors) >= 3
        ), f"应该至少有3个类方法相关错误，实际错误: {result.errors}"
